给你一个按升序排序的整数数组 num(可能包含重复数字),请你将它们分割成一个或多个子序列,其中每个子序列都由连续整数组成且长度至少为 3 。
如果可以完成上述分割,则返回 true ;否则,返回 false 。
示例 1:
输入: [1,2,3,3,4,5] 输出: True 解释: 你可以分割出这样两个连续子序列 : 1, 2, 3 3, 4, 5
示例 2:
输入: [1,2,3,3,4,4,5,5] 输出: True 解释: 你可以分割出这样两个连续子序列 : 1, 2, 3, 4, 5 3, 4, 5
示例 3:
输入: [1,2,3,4,4,5] 输出: False
这道题可以使用贪心算法来解决。
具体地,对于数组中的每个数,都要尽可能地将它添加到已有的子序列中,如果没有合适的子序列,则新建一个子序列。
假设我们使用两个哈希表 dict1 和 dict2,其中 dict1[i] 表示数字 i 可以作为某个子序列的末尾;dict2[i] 表示数字 i 在所有子序列中还剩下的个数。初始化时,dict1 和 dict2 中的所有元素都是 0。
遍历数组中的每个数,对于当前数 i,分两种情况:
如果 i 在 dict2 中的值大于 0,说明它可以添加到某个子序列的末尾。因此,我们先检查是否存在以 i-1 结尾的子序列,即是否存在 dict1[i-1] > 0。如果存在,则将数字 i 添加到该子序列中,即将 dict1[i-1] 减 1,并将 dict1[i] 加 1,同时将 dict2[i] 减 1。如果不存在,则新建一个长度为 3 的子序列,即 dict1[i]=1,dict1[i+1]=1,dict1[i+2]=1,同时将 dict2[i] 减 1,dict2[i+1] 减 1,dict2[i+2] 减 1。
如果 i 在 dict2 中的值等于 0,说明它已经被用完了,跳过即可。
在遍历完数组之后,如果没有剩余的数字,说明可以分割成若干个子序列,返回 true;否则,返回 false。
var isPossible = function (nums) {
let dict1 = {}; // 存储以 i 结尾的子序列的数量
let dict2 = {}; // 存储数字 i 在所有子序列中还剩下的个数
for (let num of nums) {
dict2[num] = (dict2[num] || 0) + 1; // 统计数字 num 的个数
}
for (let num of nums) {
if (dict2[num] == 0) {
continue;
}
if (dict1[num - 1] > 0) {
// 如果存在以 num-1 结尾的子序列,则将 num 添加到该子序列中
dict1[num - 1] -= 1;
dict1[num] = (dict1[num] || 0) + 1;
dict2[num] -= 1;
} else if (dict2[num + 1] > 0 && dict2[num + 2] > 0) {
// 如果不存在以 num-1 结尾的子序列,则新建一个长度为 3 的子序列
dict2[num] -= 1;
dict2[num + 1] -= 1;
dict2[num + 2] -= 1;
dict1[num + 2] = (dict1[num + 2] || 0) + 1;
} else {
return false; // 无法将 num 添加到已有的子序列中,返回 false
}
}
return true;
};
// @lc code=end